package com.navi.loaddata.core.repository.impl;


import com.navi.loaddata.core.oracleEntity.array.EtlArrayGlassV;
import com.navi.loaddata.core.repository.NaviRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.EntityManager;
import javax.persistence.LockModeType;
import javax.persistence.Query;
import java.util.Collection;
import java.util.List;

//@EnableAutoConfiguration
//@ComponentScan
public abstract class NaviRepositoryImpl implements NaviRepository {

    //
    public static final String DELETE = "DELETE";
    public static final String UPDATE = "UPDATE";
    public static final String INSERT = "INSERT";

    private Logger logger = LoggerFactory.getLogger(NaviRepositoryImpl.class);


    @Override
    public <T, ID> T get(Class<T> clazz, ID id) {
        return getEntityManager().find(clazz, id);
    }

    /**
     * 需要加锁的地方，必须在方法前声明事务注解@Transactional ,否则锁将不会成功
     * PS: 之前ICIM版本的库之所以不用@Transactional，是因为在AOP中开启了事务。
     * 这样做的坏处是，有些查询的业务是不需要事务的，全部开启反而降低了系统的效能
     *
     * @param id
     * @return
     */
    @Override
    public <T, ID> T getWithLock(Class<T> clazz, ID id) {

        final EntityManager entityManager = getEntityManager();
        T t = entityManager.find(clazz, id);
        entityManager.lock(t, LockModeType.PESSIMISTIC_WRITE);
        return t;
    }

    @Override
    public <T> T uniqueResult(Class<T> clazz, String hql) {
        return (T) getEntityManager().createQuery(hql).getSingleResult();
    }

    @Override
    public <T> Query createQuery(Class<T> clazz, String hqlString) {
        final Query query = getEntityManager().createQuery(hqlString, clazz);
        return query;
//        return query.unwrap(Query.class);

    }

    @Override
    public <T> Query createNativeQuery(Class<T> clazz, String sqlString) {
        return getEntityManager().createNativeQuery(sqlString, clazz);
    }

    @Override
    public Query createNativeQuery(String sqlString) {
        return getEntityManager().createNativeQuery(sqlString);
    }

    @Override
    public long count(String countSql) {
        return (Long) getEntityManager().createQuery(countSql).getSingleResult();
    }

    @Override
    public <T> List<T> find(Class<T> clazz, String hql) {
        //return this.createQuery(clazz, hql).setMaxResults(200).getResultList();
        return this.createQuery(clazz, hql).getResultList();
    }

    @Override
    public <T> List<T> findBySql(Class<T> clazz, String sql) {
        return getEntityManager().createNativeQuery(sql, clazz).getResultList();
    }

    @Override
    public <T> List<T> list(Class<T> clazz, String hql, Object... params) {
        Query query = this.createQuery(clazz, hql);
        for (int i = 0; i < params.length; i++) {
            query.setParameter(i + 1, params[i]);
        }
        return query.getResultList();
    }

    @Override
    public List findBySQL(String sql) {
        return getEntityManager().createNativeQuery(sql).getResultList();
    }

    public List findBySQL(Boolean isString, String sql) {
        return getEntityManager().createNativeQuery(sql).getResultList();
//        return this.findBySQL(sql).stream().map(objects -> objects[0].toString()).collect(Collectors.toList());
    }

    /**
     * 需要加锁的地方，必须在方法前声明事务注解@Transactional ,否则锁将不会成功
     * PS: 之前icim版本的库之所以不用，是因为在AOP中开启了事务。
     * 这样做的坏处时，有些查询的业务是不需要事务的，全部开启反而降低了系统的效能
     *
     * @param hql
     * @param params
     * @return
     */
    @Override
    public <T> List<T> listWithLock(Class<T> clazz, String hql, Object... params) {
        Query query = this.createQuery(clazz, hql);

        for (int i = 0; i < params.length; i++) {
            query.setParameter(i + 1, params[i]);
        }
        final List list = query.getResultList();
        list.forEach(entity -> getEntityManager().lock(entity, LockModeType.PESSIMISTIC_WRITE));
        return list;
    }


    public <T> void save(T entity) {
        getEntityManager().persist(entity);
        flush();
    }

    @Override
    public <T> void save(Collection<T> entities) {
        getEntityManager().persist(entities);
        flush();
    }

    @Override
    public <T> void saveAll(List<T> entities) {
        entities.forEach(e->getEntityManager().persist(e));
        flush();
    }

    @Override
    public <T> void update(T entity) {
        T s = getEntityManager().merge(entity);
        flush();


    }

    @Override
    public <T> void update(Collection<T> entities) {
        entities.forEach(entity -> {
            getEntityManager().merge(entity);
        });
        flush();
    }

/*    public <S extends BaseEntity> List<S> update(List<S> entityList) {
        entityList.forEach(e -> {
            getEntityManager().merge(e);
            setEntity(e, UPDATE);
            sendHis(e);
        });
        flush();

        return entityList;
    }*/

    //    public <T extends BaseEntity,ID> void delete(ID id)
    @Override
    public <T, ID> void delete(Class<T> clazz, ID id) {
        T entity = this.get(clazz, id);
        getEntityManager().remove(entity);
        flush();


    }

    @Override
    public <T> void delete(T entity) {

        EntityManager em = getEntityManager();

        em.remove(em.contains(entity) ? entity : em.merge(entity));
        // getEntityManager().remove(entity);
        flush();

    }

    @Override
    public <T> void delete(Collection<T> entities) {
        getEntityManager().remove(entities);
        flush();
    }

    @Override
    public <T> void deleteSessionView() {
        getEntityManager().createQuery("delete from ETL_ARRAY_GLASS_V");
        createQuery(EtlArrayGlassV.class, "delete from ETL_ARRAY_CHIP_V");
        createQuery(EtlArrayGlassV.class, "delete from ETL_ARRAY_DEFECT_V");

        flush();
    }

    public void flush() {
        getEntityManager().flush();

    }



}